#include "05_TCPconnection.hpp"
#include <stdlib.h>
#include <sys/socket.h> //socket | bind | connect | listen | accept | send | recv
#include <unistd.h>     //close 因为还能关闭文件和管道，所以独自升级了                        
#include <cstring>
#include <iostream>
#include <sstream>

inline void error_msg(const char* msg = "", int ret_flag = -1)
{
    char buff[256] = {0};
    snprintf(buff, sizeof(buff), "%s | %d | %s : %s", __FILE__, __LINE__, __FILE__, msg);
    perror(buff);
}

namespace xy
{
TCPconnection::TCPconnection(int fd)
    :_sock(fd)
    ,_sockIO(fd)
    ,_localAddr(get_local_address())
    ,_peerAddr(get_peer_address()){}

InetAddress TCPconnection::get_local_address()
{
    // 这么写我也不晓得返回了什么...
    //return _localAddr;
    
    struct sockaddr_in temp_addr;
    //memset(temp_addr, 0, sizeof(temp_addr));    // memset的第一个参数需要指针
    memset(&temp_addr, 0, sizeof(temp_addr));     // memset定义在cstring中
    
    // 第三个参数需要socklen_t*类型，用于传入传出地址长度，应添加地址符并显示转换类型
    //int ret = getsockname(_sock.get_fd(), (struct sockaddr*)&temp_addr, sizeof(temp_addr)); }
    socklen_t len = sizeof(temp_addr);    
    int ret = getsockname(_sock.get_fd(), (struct sockaddr*)&temp_addr, &len); 

    if(ret == -1)
    {
        error_msg("getsockname error");
        exit(EXIT_FAILURE);
    }

    return InetAddress(temp_addr);  // 此处需要InetAddress(struct sockadd_in构造函数)
}

InetAddress TCPconnection::get_peer_address()
{
    struct sockaddr_in temp_addr;
    memset(&temp_addr, 0, sizeof(temp_addr));     // memset定义在cstring中
    
    socklen_t len = sizeof(temp_addr);    
    int ret = getpeername(_sock.get_fd(), (struct sockaddr*)&temp_addr, &len); 

    if(ret == -1)
    {
        error_msg("getpeername error");
        exit(EXIT_FAILURE);
    }

    return InetAddress(temp_addr);  // 此处需要InetAddress(struct sockadd_in构造函数)
}

void TCPconnection::send(const std::string& msg)
{
    if(msg.size() > 0)
    {
        _sockIO.sendn(msg.c_str(), msg.size());
    }
}

std::string TCPconnection::receive()
{
    char buff[64 * 1024] = {0};      // 栈上开辟64K字节
    int ret = _sockIO.read_line(buff, sizeof(buff));
    if(ret == -1)
    {
        error_msg("receive");
        exit(EXIT_FAILURE);
    }

    return buff;
}

void TCPconnection::shutdown()
{
    close(_sock.get_fd());
}

bool TCPconnection::is_closed()
{
    return _sockIO.recv_peek() == 0;
}

// 仅仅打印就违反了to_string()的设定，此处使用sstream
std::string TCPconnection::tostring() const
{
#if 0
    printf("The information of TCPconnection: \n");
    printf("sockfd: %d\n", _sock.get_fd());
    printf("local_addr: %s\n", _localAddr.get_ip().c_str());
    printf("local_port: %d\n", _localAddr.get_port());
    printf("peer_addr: %s\n", _peerAddr.get_ip().c_str());
    printf("peer_port: %d\n", _peerAddr.get_port());
#endif

    std::stringstream ss;
    ss << "The information of TCPconnection: \n";
    ss << "sockfd: " << _sock.get_fd() << "\n";
    ss << "local_addr: " << _localAddr.get_ip() << "\n";
    ss << "local_port: " << _localAddr.get_port() << "\n";
    ss << "peer_addr: " << _peerAddr.get_ip() << "\n";
    ss << "peer_port: " << _peerAddr.get_port() << "\n";

    return ss.str();
}

}

